
<div class="toolbar-container web colorblind-check">
    <div class="toolbar-caption">{% trans "colorblind / caption" %} <i class="fa fa-cog fa-spin prog-ress hide"></i></div>
    <div class="button active" data-type="normal">
        <img src="/static/img/colorblind-check/norm.png" />
        Norm
    </div>
    <div class="button" data-type="deuteranopia">
        <img src="/static/img/colorblind-check/deut.png" />
        <i class="warning fa fa-exclamation-triangle" aria-hidden="true"></i>
        Deut
        <div class="more-info">
            <span class="arrow">▲</span><br>
            {{ "colorblind / info / deut" | trans | raw }}
        </div>
    </div>
    <div class="button" data-type="protanopia">
        <img src="/static/img/colorblind-check/prot.png" />
        <i class="warning fa fa-exclamation-triangle" aria-hidden="true"></i>
        Prot
        <div class="more-info">
            <span class="arrow">▲</span><br>
            {{ "colorblind / info / prot" | trans | raw }}
        </div>
    </div>
    <div class="button" data-type="tritanopia">
        <img src="/static/img/colorblind-check/trit.png" />
        <i class="warning fa fa-exclamation-triangle" aria-hidden="true"></i>
        Trit
        <div class="more-info">
            <span class="arrow">▲</span><br>
            {{ "colorblind / info / trit" | trans | raw }}
        </div>
    </div>
</div>

<script type="text/javascript" src="/static/js/misc/color-blind.js"></script>

<div id="color-preview">

</div>

<style type="text/css">
.color {
    display: inline-block;
    width: 20px;
    height: 20px;
}

</style>

<div style="display:flex;width:600px;">
    <div id="OK" style="width:45%"></div>
    <div id="ERR" style="width:45%"></div>
</div>

<script type="text/javascript">

require(['chroma', 'd3'], function(chroma, d3) {

    var state = { sim: 'normal' };
    var firstLoad = true;
    var runTestLater = _.debounce(runTests, 1000);
    var lastColors = d3.set();
    var color_lt = {};

    var __dw;

    var progress = $('.colorblind-check .toolbar-caption .prog-ress'),
        warning = $('.colorblind-check .toolbar-caption .warning');

    $('#colorblind-type').change(function() {
        state.sim = $('#colorblind-type').val();
         color_lt = {};
        forceRerender();
    })

    initIframe();

    function forceRerender() {
        $('#iframe-vis').get(0).contentWindow.__dw.render();
        $('#iframe-vis').get(0).contentWindow.dispatchEvent(new Event('resize'));
    }

    function difference(col_a, col_b) {
        return 0.5 * (chroma.deltaE(col_a, col_b) + chroma.deltaE(col_b, col_a));
    }

    function initIframe() {
        var iframe = $('#iframe-vis').get(0),
            iframeWin = iframe.contentWindow,
            iframeDoc = iframe.contentDocument;

        if (!iframeWin.__dw) return setTimeout(initIframe, 5);

        __dw = iframeWin.__dw;

        if (__dw.colorMapInjected) return;
        iframeWin.__dwColorMap = colorMap;
        __dw.colorMapInjected = true;

        chart.onChange(function() {
            // console.log('-- onChange --');
            progress.removeClass('hide');
            warning.addClass('hide');
            setTimeout(function() {
                progress.addClass('hide');
            }, 4000);
        });
        progress.removeClass('hide');
    }

    function colorMap(color) {
        // console.log('cm',lastColors.size());
        if (state.sim == 'normal' || !color || color == 'none' ||
            color == 'transparent' || color == 'auto' || !color) return color;
        var k = String(color);
        lastColors.add(k);
        if (color_lt[k] !== undefined) return color_lt[k];
        try {
            color = chroma(k).hex();
            return (color_lt[k] = blinder[state.sim](color));
        } catch (e) {
            // console.log('unknown color', color);
            return color;
        }
    }

    var btns = $('.colorblind-check .button').click(function(e) {
        var btn = $(e.target),
            type = btn.data('type');
        btns.removeClass('active');
        btn.addClass('active');
        state.sim = type;
        color_lt = {};
        forceRerender();
    });

    window.addEventListener('message', function(evt) {
        if (evt.data == 'datawrapper:vis:reload') {
            initIframe();
        }
        if (evt.data == 'datawrapper:vis:rendered') {
            progress.removeClass('hide');
            runTests();
        }
    });

    function runTests() {
        // get list of all colors used in last run
        var colors = __dw.vis.colorsUsed();
        if (colors.length > 30) {
            colors = colors.map(function(c) {
                var col = chroma(c);
                return {
                    raw: c,
                    color: col,
                    hue: col.get('lch.h')
                };
            }).sort(function(a,b) {
                return a.hue - b.hue;
            }).map(function(c) {
                return c.color;
            });
            // sample colors from hue gradient
            sample = chroma.scale(colors).colors(20);
        } else {
            // use all colors
            sample = colors;
        }
        // var sample = _.sample(colors, 50);

        if (!sample.length) {
            // wait a second
            setTimeout(runTests,1000);
            return;
        }

        // $('#color-preview').html('');
        // sample.forEach(function(col) {
        //     $('<div class="color" style="background:'+col+'"></>')
        //         .appendTo('#color-preview');
        // });

        // auto-test 3 simulations
        warning.addClass('hide');
        progress.addClass('hide');

        var res = {};

        if (colors.length > 1) {
            $('.colorblind-check .button')
                .removeClass('warning')
                .each(function(i,el) {
                    el = $(el);
                    if (el.data('type') == 'normal') return;
                    if (!testSample(sample, el.data('type'))) {
                        el.addClass('warning');
                        warning.removeClass('hide');
                        res[el.data('type')] = 1;
                    } else {
                        res[el.data('type')] = 0;
                    }
                });
        } else {
            // just one color
            progress.addClass('hide');
            warning.addClass('hide');
            $('.colorblind-check .button').removeClass('warning');
            res = { deuteranopia: 0, protanopia: 0, tritanopia: 0 };
        }


        if (location.search == '?cbchk') {
            if (chart.save) {
                chart.set('metadata.colorblind', res);
            } else {
                setTimeout(function() {
                    chart.set('metadata.colorblind', res);
                }, 3000);
            }
        }

        color_lt = {};
    }

    function testSample(sample, type) {
        var ok = 0, notok = 0;
        var ratio_thres = 5;
        var smallest_percievable_distance = 9.2;
        var k = sample.length;
        if (!k) {
            // console.log('no sample', type);
            return true;
        }
        // compute distances between colors
        for (var a=0; a < k; a++) {
            for (var b=a+1; b < k; b++) {
                try {
                    var col_a = chroma(sample[a]);
                    var col_b = chroma(sample[b]);
                } catch (e) {
                    // something odd with either of the colors, ignore
                    continue;
                }
                var dst_norm = difference(col_a, col_b);
                if (dst_norm < smallest_percievable_distance) continue;
                var a_sim = blinder[type](col_a.hex());
                var b_sim = blinder[type](col_b.hex());
                var dst_sim = difference(a_sim, b_sim);
                var is_not_ok = dst_norm/dst_sim > ratio_thres && dst_sim < smallest_percievable_distance;
                if (is_not_ok) {
                    // console.log(type, sample[a],sample[b],a_sim+'',b_sim+'', dst_norm, dst_sim, dst_norm/dst_sim);
                }
                // count combinations that are problematic
                if (is_not_ok) notok++; else ok++;
            }
        }
        // console.log(type, notok/(ok+notok));
        // compute share of problematic samples
        return notok/(ok+notok) < 0.03;
    }

});


</script>

